﻿namespace AY38910
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Text;

    public static class StreamExtensions
    {
        private const int IntSize = sizeof(int);

        private const int UShortSize = sizeof(ushort);

        private const int ShortSize = sizeof(short);

        private const int UIntSize = sizeof(uint);

        public static byte[] ReadBytes(this Stream stream, int count)
        {
            var bytes = new byte[count];
            stream.Read(bytes, 0, count);
            return bytes;
        }

        /// <summary>
        /// Reads a stream of data until it gets to the value 0x00
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static string ReadString(this Stream stream)
        {
            var builder = new StringBuilder();
            while (true)
            {
                var val = stream.ReadByte();
                if (val == -1)
                {
                    // End of Stream
                    break;
                }

                var byteValue = (byte)val;
                char character = Convert.ToChar(byteValue);
                if (character == Char.MinValue)
                {
                    break;
                }

                builder.Append(character);
            }

            return builder.ToString();
        }

        public static string ReadString(this Stream stream, int size)
        {
            var buffer = new byte[size];
            stream.Read(buffer, 0, size);
            return Encoding.ASCII.GetString(buffer);
        }

        public static short ReadInt16(this Stream stream, bool changeEndian = false)
        {
            var buffer = new byte[ShortSize];
            stream.Read(buffer, 0, ShortSize);

            // Need to reverse it to fix the endian
            if (changeEndian)
            {
                Array.Reverse(buffer);
            }

            return BitConverter.ToInt16(buffer, 0);
        }

        public static short GetAddress(this Stream stream)
        {
            return (short)(stream.Position + stream.ReadInt16(true));
        }

        public static ushort ReadUInt16(this Stream stream, bool changeEndian = false)
        {
            var buffer = new byte[UShortSize];
            stream.Read(buffer, 0, UShortSize);

            // Need to reverse it to fix the endian
            if (changeEndian)
            {
                Array.Reverse(buffer);
            }

            return BitConverter.ToUInt16(buffer, 0);
        }

        public static uint ReadUInt32(this Stream stream, bool changeEndian = false)
        {
            var buffer = new byte[UIntSize];
            stream.Read(buffer, 0, UIntSize);

            // Need to reverse it to fix the endian
            if (changeEndian)
            {
                Array.Reverse(buffer);
            }

            return BitConverter.ToUInt32(buffer, 0);
        }

        public static int ReadInt32(this Stream stream, bool changeEndian = false)
        {
            var buffer = new byte[IntSize];
            stream.Read(buffer, 0, IntSize);

            // Need to reverse it to fix the endian
            if (changeEndian)
            {
                Array.Reverse(buffer);
            }

            return BitConverter.ToInt32(buffer, 0);
        }
    }
}
